package com.gitee.xhs.sourceIterator;

import cn.hutool.core.date.DateUtil;
import com.gitee.xhs.enums.OnTimeEnum;
import com.gitee.xhs.enums.RegularEnum;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.Serializable;
import java.util.Date;
import java.util.Iterator;

import static com.gitee.xhs.enums.OnTimeEnum.SECOND;
import static com.gitee.xhs.enums.RegularEnum.REGULAR;
import static com.gitee.xhs.enums.RegularEnum.UNREGULAR;

/**
 * @author BigHead
 * @date 2022/7/25 16:09
 * @description AbstractRateLimitedIterator
 */
public abstract class AbstractRateLimitedIterator<IT, T extends AbstractSourceIterator<IT>> implements Iterator<IT>, Serializable {

    private static final Logger logger = LoggerFactory.getLogger(AbstractRateLimitedIterator.class);

    protected boolean initIterator = true;
    protected final AbstractSourceIterator<IT> inner;
    protected Integer groupDataNum = 1;
    protected OnTimeEnum onTimeEnum = SECOND;
    protected Integer intervalTime = 1;
    protected RegularEnum regularEnum = UNREGULAR;


    protected Integer sendGroupDataNum = 0;
    protected Long readySendTimeStamp;
    protected Long justSendTimeStamp;

    public AbstractRateLimitedIterator(AbstractSourceIterator<IT> inner) {
        this.inner = inner;
        this.readySendTimeStamp = initSendTimeStamp();
        this.justSendTimeStamp = readySendTimeStamp;
    }

    public AbstractRateLimitedIterator(AbstractSourceIterator<IT> inner, Integer groupDataNum, OnTimeEnum onTimeEnum, Integer intervalTime, RegularEnum regularEnum) {
        this.inner = inner;
        if (null != groupDataNum) {
            this.groupDataNum = groupDataNum;
        }
        if (null != onTimeEnum) {
            this.onTimeEnum = onTimeEnum;
        }
        if (null != intervalTime) {
            this.intervalTime = intervalTime;
        }
        if (null != regularEnum) {
            this.regularEnum = regularEnum;
        }
        this.readySendTimeStamp = initSendTimeStamp();
        this.justSendTimeStamp = readySendTimeStamp;
    }

    protected Long initSendTimeStamp() {
        long nowTimeStamp = System.currentTimeMillis();
        if (regularEnum == REGULAR) {
            switch (onTimeEnum) {
                case MINUTE: {
                    nowTimeStamp = DateUtil.beginOfMinute(new Date(nowTimeStamp)).getTime();
                    break;
                }
                case HOUR: {
                    nowTimeStamp = DateUtil.beginOfHour(new Date(nowTimeStamp)).getTime();
                    break;
                }
                case DAY: {
                    nowTimeStamp = DateUtil.beginOfDay(new Date(nowTimeStamp)).getTime();
                    break;
                }
                case MONTH: {
                    nowTimeStamp = DateUtil.beginOfMonth(new Date(nowTimeStamp)).getTime();
                    break;
                }
                case YEAR: {
                    nowTimeStamp = DateUtil.beginOfYear(new Date(nowTimeStamp)).getTime();
                    break;
                }
                default:
                    nowTimeStamp = DateUtil.beginOfSecond(new Date(nowTimeStamp)).getTime();
                    break;
            }
        }
        return handSendTimeStamp(nowTimeStamp);
    }

    protected Long handSendTimeStamp(Long sendTimeStamp) {
        Date sendDate = new Date(sendTimeStamp);
        switch (onTimeEnum) {
            case MILLISECOND: {
                return DateUtil.offsetMillisecond(sendDate, intervalTime).getTime();
            }
            case MINUTE: {
                return DateUtil.offsetMinute(sendDate, intervalTime).getTime();
            }
            case HOUR: {
                return DateUtil.offsetHour(sendDate, intervalTime).getTime();
            }
            case DAY: {
                return DateUtil.offsetDay(sendDate, intervalTime).getTime();
            }
            case MONTH: {
                return DateUtil.offsetMonth(sendDate, intervalTime).getTime();
            }
            case YEAR: {
                return DateUtil.offsetMonth(sendDate, intervalTime * 12).getTime();
            }
            default:
                return DateUtil.offsetSecond(sendDate, intervalTime).getTime();
        }
    }

    protected IT prepareIteratorData() {
        if (!initIterator && sendGroupDataNum < groupDataNum - 1) {
            sendGroupDataNum += 1;
        } else {
            while (readySendTimeStamp > System.currentTimeMillis()) {
                logger.debug("未到发送时间");
            }
            sendGroupDataNum = 0;
            // 处理时间
            justSendTimeStamp = readySendTimeStamp;
            readySendTimeStamp = handSendTimeStamp(readySendTimeStamp);
        }
        inner.iteratorTime(justSendTimeStamp);
        initIterator = false;
        return inner.next();
    }

}
